package com.hl.reflect;

import lombok.var;
import org.junit.Test;

import java.lang.reflect.*;

public class ReflectTest {

    // 三种方式获取 class 对象
    @Test
    public void test01() throws ClassNotFoundException {
        // 1. Class.forName("全类名")  （全类名=包名+类名）
        // 最常用的方式
        Class clazz01 = Class.forName("com.hl.reflect.Student");
        System.out.println("clazz01 = " + clazz01);

        // 2. 类名.class
        // 当参数传递
        Class<Student> clazz02 = Student.class;
        System.out.println("clazz02 = " + clazz02);

        // 3. 对象名.getClass()
        // 有了实例对象才能用
        Student student = new Student();
        Class clazz03 = student.getClass();
        System.out.println("clazz03 = " + clazz03);

        System.out.println("clazz01 == clazz02 = " + (clazz01 == clazz02));
        System.out.println("clazz01 == clazz03 = " + (clazz01 == clazz03));
    }

    // 获取构造器 Constructor
    @Test
    public void test02() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class clazz = Class.forName("com.hl.reflect.Student");

        System.out.println("---- 获取 所有默认的 public 修饰的构造器 ----");
        Constructor[] cons01 = clazz.getConstructors();
        for (Constructor con : cons01) {
            System.out.println(con);
        }

        System.out.println("---- 获取 所有修饰符修饰的 构造器 ----");
        Constructor[] cons02 = clazz.getDeclaredConstructors();
        for (Constructor con : cons02) {
            System.out.println(con);
        }

        System.out.println("---- 获取单个构造器，public 修饰的 ----");
        Constructor con01 = clazz.getConstructor(String.class);
        System.out.println(con01);
//        Constructor con02 = clazz.getConstructor(int.class); // 报错，非 pulic
//        System.out.println(con02);

        System.out.println("---- 获取单个构造器，任何修饰的 ----");
        Constructor con03 = clazz.getDeclaredConstructor(String.class);
        System.out.println(con03);
        Constructor con04 = clazz.getDeclaredConstructor(int.class);
        System.out.println(con04);
        Constructor con05 = clazz.getDeclaredConstructor(String.class, int.class);
        System.out.println(con05);
//        Constructor con06 = clazz.getDeclaredConstructor(int.class, String.class);// 必须按顺序
//        System.out.println(con06);

        System.out.println("---- 获取构造器的详细信息 ----");
        int modifier = con05.getModifiers();
        System.out.println("modifier = " + modifier);
        int parameterCount = con05.getParameterCount();
        System.out.println("parameterCount = " + parameterCount);
        Parameter[] parameters = con05.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println("parameter = " + parameter);
        }

        System.out.println("---- 使用构造器创建对象 ----");
        con05.setAccessible(true);// 临时取消 权限检查，即可以使用 private 构造器
        Student stu01 = (Student) con05.newInstance("zhangSan", 22);
        System.out.println(stu01);
        Student stu02 = (Student) con01.newInstance("liSi");
        System.out.println(stu02);
    }

    // 获取 字段 field
    @Test
    public void test03() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        Class clazz = Class.forName("com.hl.reflect.Student");

        System.out.println("---- 获取 所有 public 修饰的 fields ----");
        Field[] fields01 = clazz.getFields();
        for (Field field : fields01) {
            System.out.println(field);
        }

        System.out.println("---- 获取 所有修饰的 fields ----");
        Field[] fields02 = clazz.getDeclaredFields();
        for (Field field : fields02) {
            System.out.println(field);
        }

        System.out.println("---- 获取 单个 public 修饰的 field ----");
        Field gender = clazz.getField("gender");
        System.out.println(gender);

        System.out.println("---- 获取 任何 修饰的 field ----");
        Field name = clazz.getDeclaredField("name");
        System.out.println(name);

        System.out.println("---- 获取 field 的详细信息 ----");
        int modifiers = name.getModifiers();    // 修饰符
        System.out.println("modifiers = " + modifiers);
        String name1 = name.getName();          // 字段名
        System.out.println("name1 = " + name1);
        Class<?> type = name.getType();         // 字段的数据类型
        System.out.println("type = " + type);

        System.out.println("---- 获取指定 field 取值 ----");
        Student stu01 = new Student("zhangSan", 44, "男");
        name.setAccessible(true);               // 设置访问权限
        String name2 = (String) name.get(stu01);// 获取字段取值
        System.out.println("name2 = " + name2);
        String gender1 = (String) gender.get(stu01);
        System.out.println("gender1 = " + gender1);

        System.out.println("---- 设置指定 field 值 ----");
        name.set(stu01, "liSi");                // 设置值
        System.out.println("stu01 = " + stu01);
    }

    // 获取 成员方法 method
    @Test
    public void test04() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Class clazz = Class.forName("com.hl.reflect.Student");

        System.out.println("---- 获取 所有 public 修饰的 methods （包含父类） ----");
        Method[] methods01 = clazz.getMethods();
        for (Method method : methods01) {
            System.out.println(method);
        }

        System.out.println("---- 获取 所有修饰的 methods （不包含父类）----");
        Method[] methods02 = clazz.getDeclaredMethods();
        for (Method method : methods02) {
            System.out.println(method);
        }

        System.out.println("---- 获取 单个 public 修饰的 method ----");
        Method walk = clazz.getMethod("walk");
        System.out.println(walk);
//        Method sleep = clazz.getMethod("sleep");
//        System.out.println(sleep);

        System.out.println("---- 获取 任何 修饰的 method ----");
        Method sleep = clazz.getDeclaredMethod("sleep");
        System.out.println(sleep);
        Method eat01 = clazz.getDeclaredMethod("eat", String.class);
        System.out.println(eat01);
        Method eat02 = clazz.getDeclaredMethod("eat", int.class);
        System.out.println(eat02);

        System.out.println("---- 获取 method 的详细信息 ----");
        int modifiers = eat01.getModifiers();   // 获取方法的 修饰符
        System.out.println("modifiers = " + modifiers);
        String name = eat01.getName();          // 获取方法的 名字
        System.out.println("name = " + name);
        int parameterCount = eat01.getParameterCount();         // 获取方法的 参数个数
        System.out.println("parameterCount = " + parameterCount);
        Parameter[] parameters = eat01.getParameters();         // 获取方法的 参数对象
        for (Parameter parameter : parameters) {
            System.out.println("parameter = " + parameter);
        }
        Class<?>[] parameterTypes = eat01.getParameterTypes();  // 获取方法的 参数类型
        for (Class<?> parameterType : parameterTypes) {
            System.out.println("parameterType = " + parameterType);
        }
        Class<?>[] exceptionTypes = eat01.getExceptionTypes();  // 获取方法的 异常
        for (Class<?> exceptionType : exceptionTypes) {
            System.out.println("exceptionType = " + exceptionType);
        }
        Class<?> returnType = eat01.getReturnType();    // 获取方法的 返回值类型
        System.out.println("returnType = " + returnType);

        System.out.println("---- 运行 method ----");
        Student stu01 = new Student();
        eat01.setAccessible(true);
        Object result01 = eat01.invoke(stu01, "西餐");
        System.out.println("result01 = " + result01);
        String result02 = (String) eat01.invoke(stu01, "中餐");
        System.out.println("result02 = " + result02);
    }

}
